package wsi.exp;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.rygh.core.algorithm.PrecisionRecall;
import org.rygh.core.html.Html;
import org.rygh.core.html.table.HtmlTable;
import org.rygh.core.html.table.TableData;
import org.rygh.core.html.table.TableTuple;
import org.rygh.core.model.common.MapList;
import org.rygh.core.util.UIo;
import org.rygh.core.xml.UXml;
import org.rygh.core.xml.XmlLeaf;
import org.rygh.core.xml.XmlObject;
import org.rygh.core.xml.XmlParser;
import org.rygh.core.xml.XmlPath;
import org.rygh.core.xml.XmlTree;

import wsi.depend.model.Dependency;
import wsi.function.Function;
import wsi.script.AppConfig;
import wsi.ws.WebServices;

public class Exp6Dependency extends Experiment {

	private final MapList<WebServices, Dependency> goldSetMap6 = new MapList<>();
	private final MapList<WebServices, Dependency> automaticMap6 = new MapList<>();
	private final Map<WebServices, PrecisionRecall> resultMap = new HashMap<>();

	private void compare(WebServices ws) {
		List<Dependency> auto = automaticMap6.get(ws);
		List<Dependency> gold = goldSetMap6.get(ws);

		PrecisionRecall pr = new PrecisionRecall(gold.size());
		pr.setRetrieved(auto.size());

		boolean match;
		int c = 0;

		for (Dependency a : auto) {
			match = false;

			for (Dependency g : gold) {
				if (!a.getDependant().equals(g.getDependant())
						|| !a.getProvider().equals(g.getProvider()))
					continue;

				if (a.getXpath().getValue().equals(g.getXpath().getValue())) {
					match = true;
					break;
				}
			}

			if (match)
				c++;
		}

		pr.setRelevant(c);
		resultMap.put(ws, pr);
	}

	public void loadXml6(File folder, MapList<WebServices, Dependency> map) {
		for (WebServices ws : WebServices.values()) {
			String ws_name = ws.name();
			File file = null;

			for (File f : folder.listFiles(UXml.XML_FILTER)) {
				String fname = UIo.getFileNameWithoutExtension(f.getName());

				if (fname.endsWith(ws_name)) {
					file = f;
					break;
				}
			}

			if (file == null) {
				System.out.printf("[warn] exp6 file for %s does not exist.\n",
						ws_name);
				continue;
			}

			String xml = UIo.readFile(file);
			XmlParser parser = new XmlParser(xml);
			XmlTree tree = parser.parse();

			if (!parser.isValid()) {
				System.out.printf("[error] exp6 xml for %s is invalid.\n",
						ws_name);
				continue;
			}

			List<XmlLeaf> func_nodes = tree
					.getNodesByXPath("/functional_dependency/function");
			Function dependant, provider;
			Dependency dependency;
			XmlPath xpath;

			for (XmlLeaf fn : func_nodes) {
				List<XmlLeaf> dep_nodes = fn.getChildren();
				dependant = new Function(ws_name, fn.getValue().getAttribute(
						"name"));

				for (XmlLeaf dn : dep_nodes) {
					XmlObject obj = dn.getValue();
					provider = new Function(ws_name,
							obj.getAttribute("function"));
					xpath = new XmlPath(obj.getAttribute("at_xpath"));

					dependency = new Dependency(dependant, provider);
					dependency.setXpath(xpath);

					map.put(ws, dependency);
				}
			}
		}
	}

	@Override
	public void compute() {
		ExpFolderController folder = ExpFolderController.shared();

		loadXml6(folder.getGoldFolderForExp6(), goldSetMap6);
		loadXml6(folder.getFolderForExp6(), automaticMap6);

		//

		for (WebServices ws : automaticMap6.keySet()) {
			if (!goldSetMap6.containsKey(ws)) {
				System.out.printf("[warn] gold set 6 does not contain %s.\n",
						ws.name());
				continue;
			}

			compare(ws);
		}
	}

	@Override
	public String save() {
		TableData data = new TableData();
		TableTuple tuple;

		tuple = new TableTuple();
		data.add(tuple);

		tuple.add("Web Service", "Goldset Size", "Precision", "Recall");

		for (Entry<WebServices, PrecisionRecall> e : resultMap.entrySet()) {
			tuple = new TableTuple();
			data.add(tuple);

			tuple.add(e.getKey().name());

			PrecisionRecall pr = e.getValue();

			tuple.add(pr.getGoldSize());
			tuple.add(String.format("%.2f", pr.getPrecision()));
			tuple.add(String.format("%.2f", pr.getRecall()));
		}

		data.sort();

		Html html = new Html("Experiment 6");
		html.addElement(AppConfig.shared().getConfigHtml());

		appendMissingHtml(html, goldSetMap6.keySet(), automaticMap6.keySet());

		//

		HtmlTable table = new HtmlTable("Experiment 6, Functional Dependency",
				data);
		html.addElement(table);

		//

		String htmlstr = html.toString();

		ExpFolderController folder = ExpFolderController.shared();
		UIo.saveFile(new File(folder.getResultFolder(), ExpFolderController.EXP
				+ "6_result.html"), htmlstr);

		return htmlstr;
	}

}
